//
// Created by root on 11/6/18.
//

#ifndef URSAX_NETSERVER_H
#define URSAX_NETSERVER_H

#include <stdbool.h>

#include "st.h"
#include "ursax.h"

struct NetServer;
typedef void (*ServerHandler)(void* stfd, struct NetServer* ns);
typedef void (*OnConnectCB)(void* data);

struct NetServer
{
    const char* bindaddr;		// for TCP server
    const char* name;			// for UNIX Domain server
    uint16_t port, _;
    ServerHandler handler;
    st_thread_t pipe_thread;
    st_thread_t server_loop_thread;
    int pipefd_use_to_terminate[2];
    uint64_t connection_quota;
    uint32_t num_conns;
    int serverfd;
    st_netfd_t clientfd;
    bool stop_all_service;
    bool terminated;
    bool concurrent;
    bool wait_on_termination;
    unsigned char flag;
    char data[0];
};

struct OperationTable
{
    int /*code,*/ size;
    int (*handler)(st_netfd_t stfd, void* arg);
};

struct OpTableArgs
{
    struct OperationTable *ops;
    int nb_ops;
    const char *servername;
    void *data;
};

static inline struct NetServer* new_net_server(uint32_t data_size)
{
    struct NetServer* s = (struct NetServer*)zalloc(sizeof(*s) + data_size);
//	s->connection_quota = (uint64_t)-1;
    s->concurrent = true;
    return s;
}

static inline
struct NetServer* new_net_server_std(const char *server_name,
        struct OperationTable *operation_table, int nb_ops, void *data)
{
    struct NetServer* ns_out = new_net_server(sizeof(struct OpTableArgs));
    struct OpTableArgs *args = (struct OpTableArgs *)ns_out->data;
    args->ops = operation_table;
    args->nb_ops = nb_ops;
    args->servername = server_name;
    args->data = data;
    return ns_out;
}

static inline void kill_pipe_reader(struct NetServer* s)
{
    if (s->pipe_thread) {
        st_thread_interrupt(s->pipe_thread);
        s->pipe_thread = NULL;
        st_sleep(0);
    }
}

static inline void close_terminate_pipefd(struct NetServer* s)
{
    if (s->pipefd_use_to_terminate[0]) {
        close(s->pipefd_use_to_terminate[0]);
    }

    if (s->pipefd_use_to_terminate[1]) {
        close(s->pipefd_use_to_terminate[1]);
    }

    s->pipefd_use_to_terminate[0] = s->pipefd_use_to_terminate[1] = 0;
}

// ask the server loop to exit gracefully
// *IMPORTANT* this function is asynchronous-safe to use in signal handlers
int server_loop_terminate(struct NetServer* s);
uint32_t server_get_nconnections(struct NetServer* s);
int netserver(struct NetServer* s);


#endif //URSAX_NETSERVER_H
